package de.fhaugsburg.games.boardgames;

import de.fhaugsburg.games.boardgames.exceptions.GameException;
import de.fhaugsburg.games.boardgames.exceptions.OutsideBoardException;

/**
 * A universal board for boardgames, the board consists of a double array from
 * squares, each square can be empty or can has a piece on it.
 * 
 * @author r4smus
 * 
 */
public class Board<P extends IPiece, D> {

	protected Square[][] squares;

	/**
	 * Creates a new board with a specific number of squares, with depends on
	 * the number of rows and columns.
	 * 
	 * @param rows
	 * @param columns
	 */
	public Board(int rows, int columns) {
		squares = new Square[rows][columns];

		for (int row = 0; row < getHeight(); row++) {
			for (int column = 0; column < getWidth(); column++) {
				squares[row][column] = new Square<P, D>();
			}
		}
	}
	
	public Board(){
		
	}
	

	/**
	 * removes all pieces from the board.
	 */
	public void reset() {
		for (int row = 0; row < getHeight(); row++) {
			for (int column = 0; column < getWidth(); column++) {
				squares[row][column].removePiece();
			}
		}

	}

	/**
	 * put a piece on a specific Square.
	 * 
	 * @param piece
	 * @param row
	 * @param column
	 * @throws GameException 
	 */
	public void putPiece(IPiece piece, GridPoint point) throws GameException {
		if(isOnTheBoard(point))		
		squares[point.row][point.col].putPiece(piece);
		else throw new OutsideBoardException(point.col);
	}

	/**
	 * get a Piece from a specific row and column.
	 * 
	 * @param row
	 * @param column
	 * @return
	 */
	public IPiece getPiece(GridPoint point) {
		return squares[point.row][point.col].getPiece();
	}

	/**
	 * moves a piece from one square to another square.
	 * 
	 * @param fromRow
	 * @param fromColumn
	 * @param toRow
	 * @param toColumn
	 */
	public void movePiece(GridPoint fromPoint, GridPoint toPoint) {
		squares[toPoint.row][toPoint.col].putPiece(removePiece(fromPoint));
	}

	/**
	 * removes a piece from a specific square.
	 * 
	 * @param row
	 * @param column
	 * @return the removed piece
	 */
	public IPiece removePiece(GridPoint point) {
		return squares[point.row][point.col].removePiece();
	}

	/**
	 * checks if the committed position is on the board.
	 * 
	 * @param row
	 * @param column
	 * @return
	 */
	public boolean isOnTheBoard(GridPoint point) {
		if (point.row >= 0 && point.row < getWidth() && point.col >= 0 && point.col < getHeight())
			return true;
		else
			return false;
	}

	/**
	 * checks if the committed position is empty on the board.
	 * 
	 * @param row
	 * @param column
	 * @return
	 * @throws GameException 
	 */
	public boolean isEmpty(GridPoint point) throws GameException {
		if(isOnTheBoard(point)){
		if (squares[point.row][point.col].getPiece() == null)
			return true;
		else
			return false;
		}else throw new OutsideBoardException(point.col);
	}

	/**
	 * 
	 * @return the number of rows from the board.
	 */
	public int getHeight() {
		return squares.length;
	}

	/**
	 * 
	 * @return the number of columns on the board
	 */
	public int getWidth() {
		return squares[0].length;
	}
	@SuppressWarnings("unchecked")
	public void setDetails(D details, GridPoint point){
		squares[point.row][point.col].setDetails(details);
	}
	@SuppressWarnings("unchecked")
	public D getDetails(GridPoint point){
		return (D) squares[point.row][point.col].getDetails();
	}

}
